package com.course.masterservice.impl;

import com.course.component.constant.CacheConstants;
import com.course.component.constant.TokenConstants;
import com.course.component.util.ServletUtils;
import com.course.component.util.StringUtils;
import com.course.component.util.TokenUtil;
import com.course.component.util.ip.IpUtils;
import com.course.component.util.uuid.IdUtils;
import com.course.entity.User;
import com.course.masterservice.LoginTokenService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Copyright: Copyright (c)  林中小鸟  All rights reserved.
 * @author: moon
 * @date: 2022/9/15 16:25
 * @Description: **********************
 */
@Service
public class LoginTokenServiceImpl implements LoginTokenService {
    @Resource
    private RedisTemplate redisTemplate;

    protected static long MILLIS_SECOND = 60*24;

    protected static long MILLIS_MINUTE = 60 * MILLIS_SECOND;

    private static long expireTime = CacheConstants.EXPIRATION;

    private final static String ACCESS_TOKEN = CacheConstants.LOGIN_TOKEN_KEY;

    private final static Long MILLIS_MINUTE_TEN = CacheConstants.REFRESH_TIME * MILLIS_MINUTE;

    @Override
    public Map<String, Object> createToken(User loginUser)  {
        String token = IdUtils.fastUUID();
        Long userId = loginUser.getId();
        loginUser.setToken(token);
        loginUser.setUserID(userId);
        loginUser.setLoginTime(System.currentTimeMillis());
        loginUser.setIpaddr(IpUtils.getIpAddr(ServletUtils.getRequest()));
        refreshToken(loginUser);
        // 接口返回信息
        Map<String, Object> rspMap = new HashMap<String, Object>();
        String accessToken = TokenUtil.createToken(token,loginUser.toString(),(int)(expireTime));
        rspMap.put("access_token", accessToken);
        rspMap.put("expires_in", expireTime);
        return rspMap;
    }

    @Override
    public User getLoginUser() {
        return getLoginUser(ServletUtils.getRequest());
    }

    @Override
    public String getToken(HttpServletRequest request){
        // 从header获取token标识
        String token = request.getHeader(TokenConstants.AUTHENTICATION);
        return replaceTokenPrefix(token);
    }

    @Override
    public User getLoginUser(String token) {
        User user = null;
        try {
            if (StringUtils.isNotEmpty(token)) {
                String userkey = TokenUtil.getAudience(token);
                user = (User) redisTemplate.opsForValue().get(getTokenKey(userkey));
                return user;
            }
        } catch (Exception e) {
        }
        return user;
    }

    @Override
    public void setLoginUser(User loginUser) {
        if (StringUtils.isNotNull(loginUser)) {
            refreshToken(loginUser);
        }
    }

    @Override
    public void delLoginUser(String token) {
        try {
            if (StringUtils.isNotEmpty(token)) {
                String userkey = TokenUtil.getAudience(token);
                redisTemplate.delete(userkey);
            }
        } catch (Exception e) {
        }
    }

    @Override
    public void verifyToken(User loginUser) {
        long nowExpireTime = loginUser.getExpireTime();
        long currentTime = System.currentTimeMillis();
        if (nowExpireTime - currentTime <= expireTime) {
            refreshToken(loginUser);
        }
    }

    @Override
    public void refreshToken(User loginUser) {
        // 根据uuid将loginUser缓存
        String userKey = getTokenKey(loginUser.getToken());
        redisTemplate.opsForValue().set(userKey, loginUser, expireTime, TimeUnit.MINUTES);
    }

    private String getTokenKey(String token) {
        return ACCESS_TOKEN + token;
    }

    private User getLoginUser(HttpServletRequest request) {
        // 获取请求携带的令牌
        String token = getToken(request);
        return getLoginUser(token);
    }

    private String replaceTokenPrefix(String token) {
        // 如果前端设置了令牌前缀，则裁剪掉前缀
        if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX)) {
            token = token.replaceFirst(TokenConstants.PREFIX, "");
        }
        return token;
    }
}
